// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// u [author] rhyme_lph
// I [email]  rhymelph@gmail.com
// i [github] https://github.com/rhymelph

import 'package:base_plugin/base_plugin.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/leave_item_entity.dart';
import 'package:finance_app/src/entities/payslips_item_entity.dart';
import 'package:finance_app/src/http_service/http_leave_service.dart';
import 'package:finance_app/src/http_service/http_payslips_service.dart';
import 'package:finance_app/src/mixin/search_data_map_mixin.dart';
import 'package:finance_app/src/provider/dashboard_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/views/employee_provider.dart';
import 'package:finance_app/src/provider/hr_payroll/views/leave_provider.dart';
import 'package:finance_app/src/router_gen/override_route_providers.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/date_time_utils.dart';
import 'package:finance_app/src/utils/form_utils.dart';
import 'package:finance_app/src/utils/permission_utils.dart';
import 'package:finance_app/src/widgets/bottom_sheet/delete_info_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/got_it_tip_bottom_sheet.dart';
import 'package:finance_app/src/widgets/bottom_sheet/text_area_input_bottom_sheet.dart';
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:dio/dio.dart';
import '../hr_and_payroll_provider.dart';

class LeaveOperationProvider extends BaseProvider<List<LeaveItemEntity>>
    with SearchDataMapMixin<List<LeaveItemEntity>, LeaveItemEntity> {
  String operation;

  void onOperation(String operation) {
    switch (operation) {
      case 'Delete':
        _onDelete();
        break;
      case 'Approve':
        _onApprove();
        break;
      case 'Reject':
        _onReject();
        break;
      case 'Withdraw':
        _onWithdraw();
        break;
    }
  }

  void _onDelete() {
    if (currentSelectList.length == 0) return;
    List<int> ids = currentSelectList.map((e) => e.id).toList();
    obtainContext?.call((context) async {
      final result = await showDeleteLeaveBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpLeaveService.batchLeaveDelete(ids),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showLeaveDeleteSuccessBottomSheet(context);
          data.removeWhere((element) => ids.contains(element.id));
          currentSelectList.clear();
          searchData.clear();
          data = transformData(data, false);
          update();
          for (final item in ids) {
            Providers.get<HrAndPayrollProvider>(
                    RouterGenProviders.hrAndPayrollPage, null)
                ?.getChildProvider<LeaveProvider>()
                ?.deleteItem(
                  item,
                );
            if (!Config.hasPermission(PermissionUtils.homeDashboard))
              Config.dashboardProvider
                  ?.getChildProvider<HrAndPayrollProvider>()
                  ?.getChildProvider<LeaveProvider>()
                  ?.deleteItem(
                    item,
                  );
          }
          updateDashboard();
          Navigator.of(context).pop();
        }
      }
    });
  }

  void _onApprove() {
    if (currentSelectList.length == 0) return;
    List<int> ids = currentSelectList.map((e) => e.id).toList();

    obtainContext?.call((context) async {
      final result = await showApproveLeaveBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpLeaveService.batchLeaveApprove(ids),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showLeaveApprovedSuccessBottomSheet(context);
          data.removeWhere((element) => ids.contains(element.id));
          currentSelectList.clear();
          searchData.clear();
          data = transformData(data, false);
          update();
          for (final item in ids) {
            Providers.get<HrAndPayrollProvider>(
                    RouterGenProviders.hrAndPayrollPage, null)
                ?.getChildProvider<LeaveProvider>()
                ?.updateStatus(item, 'approved');
            if (!Config.hasPermission(PermissionUtils.homeDashboard))
              Config.dashboardProvider
                  ?.getChildProvider<HrAndPayrollProvider>()
                  ?.getChildProvider<LeaveProvider>()
                  ?.updateStatus(item, 'approved');
          }
          updateDashboard();
          Navigator.of(context).pop();
        }
      }
    });
  }

  void _onReject() {
    if (currentSelectList.length == 0) return;
    List<int> ids = currentSelectList.map((e) => e.id).toList();

    obtainContext?.call((context) async {
      String content =
          await showRejectLeaveRequestInputBottomSheet(context, onDone: (data) {
        Navigator.of(context).pop(data);
      });
      if (content != null) {
        bool isSuccess = false;
        await post(HttpLeaveService.batchLeaveReject(ids, content),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showLeaveRejectedSuccessBottomSheet(context);
          data.removeWhere((element) => ids.contains(element.id));
          currentSelectList.clear();
          searchData.clear();
          data = transformData(data, false);
          update();
          for (final item in ids) {
            Providers.get<HrAndPayrollProvider>(
                    RouterGenProviders.hrAndPayrollPage, null)
                .getChildProvider<LeaveProvider>()
                .updateStatus(item, 'rejected', content);
            if (!Config.hasPermission(PermissionUtils.homeDashboard))
              Config.dashboardProvider
                  ?.getChildProvider<HrAndPayrollProvider>()
                  ?.getChildProvider<LeaveProvider>()
                  ?.updateStatus(item, 'rejected', content);
          }
          updateDashboard();
          Navigator.of(context).pop();
        }
      }
    });
  }

  List<LeaveItemEntity> currentSelectList = [];

  @override
  Future<Response> get dataFuture async {
    String status = 'pending';
    if (operation == 'Withdraw') {
      status = 'upcoming';
    }
    if (Config.isStaff) {
      final employee = await Config.getEmployeeMe(this);
      return HttpLeaveService.leavesList(employee.id, status);
    }
    return HttpLeaveService.leavesList(null, status);
  }

  void onCancel() {
    obtainContext?.call((context) {
      Navigator.of(context).pop();
    });
  }

  void onSelect(LeaveItemEntity item1) {
    if (currentSelectList.contains(item1)) {
      currentSelectList.remove(item1);
    } else {
      currentSelectList.add(item1);
    }
    update();
  }

  @override
  FutureOr<List<LeaveItemEntity>> transformData(
      List<LeaveItemEntity> d, bool isCache) {
    for (final item in d) {
      DateTime start = DateTimeUtils.toDateTime(item.startDate, 'yyyy-MM-dd');
      String month = DateTimeUtils.formatDateTime(start, 'MMM');
      if (searchData.containsKey(month)) {
        searchData[month].add(item);
      } else {
        searchData[month] = [item];
      }
    }
    return super.transformData(d, isCache);
  }

  void onDeselectAll() {
    currentSelectList.clear();
    update();
  }

  void onSelectAll() {
    currentSelectList.addAll(List.from(data));
    update();
  }

  String getLeaveStatus(LeaveItemEntity e) {
    if (e.status == 'approved') {
      final dateTime = DateTime.now();
      final startTime = DateTimeUtils.toDateTime(e.startDate, 'yyyy-MM-dd');
      return startTime.isBefore(dateTime) ? null : 'Upcoming';
    }
    return FormUtils.getStatus(ReimburseModel.leave, e.status, 0);
  }

  void _onWithdraw() {
    if (currentSelectList.length == 0) return;
    List<int> ids = currentSelectList.map((e) => e.id).toList();
    obtainContext?.call((context) async {
      final result = await showWithdrawLeaveBottomSheet(context);
      if (result == true) {
        bool isSuccess = false;
        await post(HttpLeaveService.batchLeaveWithdraw(ids),
            autoHandler: AutoHandler.Toast,
            loadingTip: S.current.loading, onSuccess: (result) {
          isSuccess = true;
        });
        if (isSuccess) {
          await showLeaveWithdrawSuccessBottomSheet(context);
          data.removeWhere((element) => ids.contains(element.id));
          currentSelectList.clear();
          searchData.clear();
          data = transformData(data, false);
          update();
          for (final item in ids) {
            Providers.get<HrAndPayrollProvider>(
                    RouterGenProviders.hrAndPayrollPage, null)
                .getChildProvider<LeaveProvider>()
                .updateStatus(item, 'withdrew');
            if (!Config.hasPermission(PermissionUtils.homeDashboard))
              Config.dashboardProvider
                  ?.getChildProvider<HrAndPayrollProvider>()
                  ?.getChildProvider<LeaveProvider>()
                  ?.updateStatus(item, 'withdrew');
          }
          updateDashboard();
          Navigator.of(context).pop();
        }
      }
    });
  }

  updateDashboard() {
    Providers.get<HrAndPayrollProvider>(
            RouterGenProviders.hrAndPayrollPage, null)
        ?.getChildProvider<EmployeeProvider>()
        ?.refreshController
        ?.requestRefresh();
    if (!Config.hasPermission(PermissionUtils.homeDashboard))
      Config.dashboardProvider
          ?.getChildProvider<HrAndPayrollProvider>()
          ?.getChildProvider<EmployeeProvider>()
          ?.refreshController
          ?.requestRefresh();
  }
}
